﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using CodeNotes.Common;
using System.Text;
using System.Xml;
using System.Net;
using System.Web.Script.Serialization;
using System.Security.Cryptography;
using System.Web.Security;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace MvcCodeNotes.Controllers.api
{
    /// <summary>
    /// wxapp 的摘要说明
    /// </summary>
    public class wxapp : IHttpHandler
    {
        private string _result = string.Empty;
        public void ProcessRequest(HttpContext context)
        {

            Log.LogNote("Query String:", context.Request.QueryString.ToString(), "wxapp");

            string postStr = "";            
            Stream s = System.Web.HttpContext.Current.Request.InputStream;
            byte[] b = new byte[s.Length];
            s.Read(b, 0, (int)s.Length);
            postStr = Encoding.UTF8.GetString(b);
            Log.LogNote("Post String:", postStr, "wxapp");
            Log.LogNote("HttpMethod:", context.Request.HttpMethod.ToLower(), "wxapp");

            Wechat wc = new Wechat();
            if (context.Request.HttpMethod.ToLower() == "post")
            {

                if (!string.IsNullOrEmpty(postStr))
                {
                    //封装请求类
                    //<xml><ToUserName><![CDATA[gh_d3215341508d]]></ToUserName>
                    //    <FromUserName><![CDATA[o3YPejsEwjo2NGoxjWmFVC9KzuDE]]></FromUserName>
                    //    <CreateTime>1444977870</CreateTime>
                    //    <MsgType><![CDATA[text]]></MsgType>
                    //    <Content><![CDATA[111]]></Content>
                    //    <MsgId>6206132695305100128</MsgId>
                    //    </xml>
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(postStr);
                    XmlElement rootElement = doc.DocumentElement;

                    XmlNode MsgType = rootElement.SelectSingleNode("MsgType");

                    RequestXML requestXML = new RequestXML();
                    requestXML.ToUserName = rootElement.SelectSingleNode("ToUserName").InnerText;
                    requestXML.FromUserName = rootElement.SelectSingleNode("FromUserName").InnerText;
                    requestXML.CreateTime = rootElement.SelectSingleNode("CreateTime").InnerText;
                    requestXML.MsgType = MsgType.InnerText;
                 
                    if (requestXML.MsgType == "text")
                    {
                        requestXML.Content = rootElement.SelectSingleNode("Content").InnerText;
                    }
                    else if (requestXML.MsgType == "location")
                    {
                        requestXML.Location_X = rootElement.SelectSingleNode("Location_X").InnerText;
                        requestXML.Location_Y = rootElement.SelectSingleNode("Location_Y").InnerText;
                        requestXML.Scale = rootElement.SelectSingleNode("Scale").InnerText;
                        requestXML.Label = rootElement.SelectSingleNode("Label").InnerText;
                    }
                    else if (requestXML.MsgType == "image")
                    {
                        requestXML.PicUrl = rootElement.SelectSingleNode("PicUrl").InnerText;
                    }
                    else if (requestXML.MsgType == "event")
                    {
                        requestXML.Event = rootElement.SelectSingleNode("Event").InnerText;
                        switch (requestXML.Event)
                        {
                            case "subscribe":

                                break;
                            case "click":
                            case "CLICK":
                                requestXML.EventKey = rootElement.SelectSingleNode("EventKey").InnerText;
                                break;
                            case "view":
                                break;
                            case "scancode_push":
                            case "scancode_waitmsg":
                                requestXML.EventKey = rootElement.SelectSingleNode("EventKey").InnerText;
                                requestXML.ScanCodeInfo = rootElement.SelectSingleNode("ScanCodeInfo").InnerXml;
                                requestXML.ScanType = rootElement.SelectSingleNode("ScanCodeInfo").ChildNodes[0].InnerText;
                                requestXML.ScanResult = rootElement.SelectSingleNode("ScanCodeInfo").ChildNodes[1].InnerText;
                                break;
                            case "pic_sysphoto":
                                break;
                            case "pic_photo_or_album":
                                break;
                            case "pic_weixin":
                                break;
                            case "location_select":
                                break;
                            case "user_get_card":                                
                                break;
                            case "user_consume_card":
      
                                break;
                            default:
                                break;
                        }
                    }



                    //回复消息
                    _result = wc.ResponseMsg(requestXML);
                }
            }
            else
            {

                _result = wc.Valid();
                //_result=wc.GetOpenID();            

            }

            context.Response.ContentType = "text/plain";
            context.Response.Write(_result);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

    public class Wechat
    {
        public HttpRequest Request = HttpContext.Current == null ? null : HttpContext.Current.Request;
        public JavaScriptSerializer Serializer = new JavaScriptSerializer();
        //菜谱小程序
        public String AppId = "wxe35c40a00c16acc2";
        public String AppSecret = "344c1b8fe6ffc9dcc49e082456db6e01";
        public String Token = "arnozhang";

        public String DefaultResponseContent = "欢迎关注!";

        #region 验证签名
        public string Valid()
        {
            string echoStr = Request.QueryString["echoStr"];
            if (CheckSignature() && !string.IsNullOrEmpty(echoStr))
            {
                return echoStr;
            }
            return "";
        }

        /// <summary>
        /// 验证微信签名
        /// </summary>
        /// * 将token、timestamp、nonce三个参数进行字典序排序
        /// * 将三个参数字符串拼接成一个字符串进行sha1加密
        /// * 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信。
        /// <returns></returns>
        private bool CheckSignature()
        {
            string signature = Request.QueryString["signature"];
            string timestamp = Request.QueryString["timestamp"];
            string nonce = Request.QueryString["nonce"];
            string[] ArrTmp = { Token, timestamp, nonce };
            Array.Sort(ArrTmp);     //字典排序
            string tmpStr = string.Join("", ArrTmp);
            tmpStr = FormsAuthentication.HashPasswordForStoringInConfigFile(tmpStr, "SHA1");
            tmpStr = tmpStr.ToLower();
            if (tmpStr == signature)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        #endregion

        #region 消息返回
        /// <summary>
        /// 回复消息(微信信息返回)
        /// </summary>
        /// <param name="weixinXML"></param>
        public string ResponseMsg(RequestXML requestXML)
        {
            try
            {
                string resxml = string.Empty;
                if (requestXML.MsgType == "text")
                {

                }
                else if (requestXML.MsgType == "location")
                {

                }
                else if (requestXML.MsgType == "image")
                {

                }
                else if (requestXML.MsgType == "event")
                {
                    switch (requestXML.Event)
                    {
                        case "subscribe":
                            break;
                        case "CLICK":
                        case "click":
                            break;
                        case "view":
                            break;
                        case "scancode_push":
                            break;
                        case "scancode_waitmsg":

                            break;
                        case "pic_sysphoto":
                            break;
                        case "pic_photo_or_album":
                            break;
                        case "pic_weixin":
                            break;
                        case "location_select":
                            break;
                        default:
                            break;
                    }
                }
                return resxml;
            }
            catch (Exception ex)
            {
                return string.Empty;
            }
        }
        #endregion

        #region 获取access_token
        public string GetAccessToken()
        {

            string url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + AppId + "&secret=" + AppSecret;
            var response = HttpWebResponseUtility.CreateGetHttpResponse(url, null, string.Empty, null);
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("UTF-8"));
            string retString = myStreamReader.ReadToEnd();
            JavaScriptSerializer Serializer = new JavaScriptSerializer();
            ResponseJSON rj = Serializer.Deserialize<ResponseJSON>(retString);
            return rj.access_token;
        }

        #endregion

        #region 获取OpenID
        public string GetOpenID()
        {
            string code = Request.QueryString["code"];
            string url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + AppId + "&secret=" + AppSecret + "&code=" + code + "&grant_type=authorization_code";
            var response = HttpWebResponseUtility.CreateGetHttpResponse(url, null, string.Empty, null);
            Stream myResponseStream = response.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("UTF-8"));
            string retString = myStreamReader.ReadToEnd();
            JavaScriptSerializer Serializer = new JavaScriptSerializer();
            ResponseJSON rj = Serializer.Deserialize<ResponseJSON>(retString);
            return rj.openid;
        }
        #endregion
  

        #region 发送请求
        /// <summary>
        /// 向微信服务器发送GET请求
        /// </summary>
        /// <param name="posturl">请求地址</param>
        /// <returns></returns>
        public string CreateGetHttpResponse(string posturl)
        {
            Encoding encoding = Encoding.UTF8;
            var response = HttpWebResponseUtility.CreateGetHttpResponse(posturl, null, string.Empty, null);

            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, encoding);
            //返回结果网页（html）代码
            string content = sr.ReadToEnd();
            return content;
        }

        /// <summary>
        /// 向微信服务器发送POST请求
        /// </summary>
        /// <param name="posturl">请求地址</param>
        /// <param name="posturl">请求参数</param>
        /// <returns></returns>
        public string CreatePostHttpResponse(string posturl, string postData)
        {
            Encoding encoding = Encoding.UTF8;
            var response = HttpWebResponseUtility.CreatePostHttpResponse(posturl, postData, null, string.Empty, encoding, null);

            //直到request.GetResponse()程序才开始向目标网页发送Post请求
            Stream instream = response.GetResponseStream();
            StreamReader sr = new StreamReader(instream, encoding);
            //返回结果网页（html）代码
            string content = sr.ReadToEnd();
            return content;
        }



        #endregion

        #region 发送客服消息
        public static string SendMsg(string openid, string message)
        {
            string menu = "{\"touser\":\"" + openid + "\",\"msgtype\":\"text\",\"text\":{\"content\":\"" + message + "\"}}";
            var wc = new Wechat();
            var content = wc.CreatePostHttpResponse("https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token=" + wc.GetAccessToken(), menu);

            JavaScriptSerializer Serializer = new JavaScriptSerializer();
            var dic = Serializer.Deserialize<Dictionary<string, string>>(content);
            var retStr = string.Empty;
            if (dic.ContainsKey("errcode"))
            {
                retStr = dic["errcode"];
            }

            return content;
        }
        #endregion

        #region 辅助方法
        /// <summary>
        /// unix时间转换为datetime
        /// </summary>
        /// <param name="timeStamp"></param>
        /// <returns></returns>
        private DateTime UnixTimeToTime(string timeStamp)
        {
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timeStamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dtStart.Add(toNow);
        }

        public static DateTime staticUnixTimeToTime(string timeStamp)
        {
            DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            long lTime = long.Parse(timeStamp + "0000000");
            TimeSpan toNow = new TimeSpan(lTime);
            return dtStart.Add(toNow);
        }

        /// <summary>
        /// datetime转换为unixtime
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        private int ConvertDateTimeInt(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }
        /// <summary>
        /// 获取时间戳
        /// </summary>
        /// <returns></returns>
        public static string GetTimeStamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        /// <summary>
        /// Post 提交调用抓取
        /// </summary>
        /// <param name="url">提交地址</param>
        /// <param name="param">参数</param>
        /// <returns>string</returns>
        public string webRequestPost(string url, string param)
        {
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(param);

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url + "?" + param);
            req.Method = "Post";
            req.Timeout = 120 * 1000;
            req.ContentType = "application/x-www-form-urlencoded;";
            req.ContentLength = bs.Length;

            using (Stream reqStream = req.GetRequestStream())
            {
                reqStream.Write(bs, 0, bs.Length);
                reqStream.Flush();
            }
            using (WebResponse wr = req.GetResponse())
            {
                //在这里对接收到的页面内容进行处理 

                Stream strm = wr.GetResponseStream();

                StreamReader sr = new StreamReader(strm, System.Text.Encoding.UTF8);

                string line;

                System.Text.StringBuilder sb = new System.Text.StringBuilder();

                while ((line = sr.ReadLine()) != null)
                {
                    sb.Append(line + System.Environment.NewLine);
                }
                sr.Close();
                strm.Close();
                return sb.ToString();
            }
        }

        public static string SHA1_Hash(string str_sha1_in)
        {
            SHA1 sha1 = new SHA1CryptoServiceProvider();
            byte[] bytes_sha1_in = UTF8Encoding.Default.GetBytes(str_sha1_in);
            byte[] bytes_sha1_out = sha1.ComputeHash(bytes_sha1_in);
            string str_sha1_out = BitConverter.ToString(bytes_sha1_out);
            str_sha1_out = str_sha1_out.Replace("-", "");
            return str_sha1_out;
        }

        //MD5加密程序（32位小写）
        public static string MD5Encrypt(string str)
        {
            byte[] result = Encoding.Default.GetBytes(str);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] output = md5.ComputeHash(result);
            String md = BitConverter.ToString(output).Replace("-", "");
            return md.ToLower();
        }

        #endregion
    }

    public class RequestXML
    {
        private string toUserName;
        /// <summary>
        /// 消息接收方微信号，一般为公众平台账号微信号
        /// </summary>
        public string ToUserName
        {
            get { return toUserName; }
            set { toUserName = value; }
        }

        private string fromUserName;
        /// <summary>
        /// 消息发送方微信号
        /// </summary>
        public string FromUserName
        {
            get { return fromUserName; }
            set { fromUserName = value; }
        }

        private string createTime;
        /// <summary>
        /// 创建时间
        /// </summary>
        public string CreateTime
        {
            get { return createTime; }
            set { createTime = value; }
        }

        private string msgType;
        /// <summary>
        /// 信息类型 地理位置:location,文本消息:text,消息类型:image
        /// </summary>
        public string MsgType
        {
            get { return msgType; }
            set { msgType = value; }
        }

        private string content;
        /// <summary>
        /// 信息内容
        /// </summary>
        public string Content
        {
            get { return content; }
            set { content = value; }
        }

        private string location_X;
        /// <summary>
        /// 地理位置纬度
        /// </summary>
        public string Location_X
        {
            get { return location_X; }
            set { location_X = value; }
        }

        private string location_Y;
        /// <summary>
        /// 地理位置经度
        /// </summary>
        public string Location_Y
        {
            get { return location_Y; }
            set { location_Y = value; }
        }

        private string scale;
        /// <summary>
        /// 地图缩放大小
        /// </summary>
        public string Scale
        {
            get { return scale; }
            set { scale = value; }
        }

        private string label;
        /// <summary>
        /// 地理位置信息
        /// </summary>
        public string Label
        {
            get { return label; }
            set { label = value; }
        }

        private string picUrl;
        /// <summary>
        /// 图片链接，开发者可以用HTTP GET获取
        /// </summary>
        public string PicUrl
        {
            get { return picUrl; }
            set { picUrl = value; }
        }

        private string _event;
        /// <summary>
        /// 推送事件，菜单的响应动作类型
        /// </summary>
        public string Event
        {
            get { return _event; }
            set { _event = value; }
        }

        private string eventKey;
        /// <summary>
        /// 事件KEY值，由开发者在创建菜单时设定
        /// </summary>
        public string EventKey
        {
            get { return eventKey; }
            set { eventKey = value; }
        }

        private string scanCodeInfo;
        /// <summary>
        /// 扫描信息
        /// </summary>
        public string ScanCodeInfo
        {
            get { return scanCodeInfo; }
            set { scanCodeInfo = value; }
        }

        private string scanType;
        /// <summary>
        /// 扫描类型，一般是qrcode
        /// </summary>
        public string ScanType
        {
            get { return scanType; }
            set { scanType = value; }
        }

        private string scanResult;
        /// <summary>
        /// 扫描结果，即二维码对应的字符串信息
        /// </summary>
        public string ScanResult
        {
            get { return scanResult; }
            set { scanResult = value; }
        }

    }

    public class ResponseJSON
    {
        public string errcode { get; set; }
        public string errmsg { get; set; }
        public string access_token { get; set; }
        public string expires_in { get; set; }
        public string refresh_token { get; set; }
        public string openid { get; set; }
        public string scope { get; set; }
    }

    #region Http请求方法

    public class HttpWebResponseUtility
    {
        private static readonly string DefaultUserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";
        /// <summary>  
        /// 创建GET方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <returns></returns>  
        public static HttpWebResponse CreateGetHttpResponse(string url, int? timeout, string userAgent, CookieCollection cookies)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "GET";
            request.UserAgent = DefaultUserAgent;
            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            return request.GetResponse() as HttpWebResponse;
        }
        /// <summary>  
        /// 创建POST方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <returns></returns>  
        public static HttpWebResponse CreatePostHttpResponse(string url, IDictionary<string, string> parameters, int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request = null;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            else
            {
                request.UserAgent = DefaultUserAgent;
            }

            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            //如果需要POST数据  
            if (!(parameters == null || parameters.Count == 0))
            {
                StringBuilder buffer = new StringBuilder();
                int i = 0;
                foreach (string key in parameters.Keys)
                {
                    if (i > 0)
                    {
                        buffer.AppendFormat("&{0}={1}", key, parameters[key]);
                    }
                    else
                    {
                        buffer.AppendFormat("{0}={1}", key, parameters[key]);
                    }
                    i++;
                }
                byte[] data = requestEncoding.GetBytes(buffer.ToString());
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }
            return request.GetResponse() as HttpWebResponse;
        }

        /// <summary>  
        /// 创建POST方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="postData">post字符串数据</param>  
        /// <param name="timeout">请求的超时时间</param>  
        /// <param name="userAgent">请求的客户端浏览器信息，可以为空</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <returns></returns>  
        public static HttpWebResponse CreatePostHttpResponse(string url, string postData, int? timeout, string userAgent, Encoding requestEncoding, CookieCollection cookies)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request = null;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }

            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";

            if (!string.IsNullOrEmpty(userAgent))
            {
                request.UserAgent = userAgent;
            }
            else
            {
                request.UserAgent = DefaultUserAgent;
            }

            if (timeout.HasValue)
            {
                request.Timeout = timeout.Value;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            //如果需要POST数据  
            if (!string.IsNullOrEmpty(postData))
            {
                byte[] data = requestEncoding.GetBytes(postData);
                using (Stream stream = request.GetRequestStream())
                {
                    stream.Write(data, 0, data.Length);
                }
            }
            return request.GetResponse() as HttpWebResponse;
        }


        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }


    }

    #endregion
}